﻿using System;
using System.Collections.Generic;
using Commons.Events;
using Commons.Models.OperationsContext;
using Commons.Models.Stats;
using Commons.Models.TradeValues;
using Commons.Services.Functions;
using Commons.Services.Stats;

namespace Commons.Services.TradeValues
{
	public delegate void EarnStatHandler (object sender, EarnStatEventArgs e);
	public delegate void SpendStatHandler (object sender, SpendStatEventArgs e);

	public class UserStatTradeValueProcessor : TradeValueProcessor
	{
		public IUserStatsService UserStatsService { protected get; set; }
		public IFunctionEvaluator FunctionEvaluator { protected get; set; }

		public event EarnStatHandler statEarned;
		public event SpendStatHandler statSpent;

		public override IEnumerable<CostStatus> GetCostsStatus(ITradeValue value, IOperationContext context, int quantity)
		{
			UserStatTradeValue tradeValue = NormalizeTradeValue(value as UserStatTradeValue, context, quantity);
			UserStats stats = UserStatsService.GetStats();
			int currentValue = stats.GetStat<IStat>(tradeValue.Unit).Value;
			int missingQuantity = Math.Max(0, tradeValue.Delta - currentValue);

			yield return new CostStatus(tradeValue, missingQuantity);
		}

		public override IEnumerable<ITradeValue> PreProcessCost(ITradeValue value, IOperationContext context)
		{
			yield return NormalizeTradeValue(value as UserStatTradeValue, context);
		}

		public override IEnumerable<ITradeValue> ProcessCost(ITradeValue value, IOperationContext context, int quantity)
		{
			UserStatTradeValue tradeValue = NormalizeTradeValue(value as UserStatTradeValue, context, quantity);
			UserStats stats = UserStatsService.GetStats();
			IStat stat = stats.GetStat<IStat>(tradeValue.Unit);
			stat.Substract(tradeValue.Delta);
			UserStatsService.UpdateStats(stats);

			if (statSpent != null)
			{
				statSpent(this, new SpendStatEventArgs(tradeValue.Unit, tradeValue.Delta));
			}

			return new ITradeValue[] { tradeValue };
		}

		public override IEnumerable<ITradeValue> PreProcessReward(ITradeValue value, IOperationContext context)
		{
			yield return NormalizeTradeValue(value as UserStatTradeValue, context);
		}

		public override IEnumerable<ITradeValue> ProcessReward(ITradeValue value, IOperationContext context, int quantity)
		{
			UserStatTradeValue tradeValue = NormalizeTradeValue(value as UserStatTradeValue, context, quantity);
			UserStats stats = UserStatsService.GetStats();
			IStat stat = stats.GetStat<IStat>(tradeValue.Unit);
			stat.Add(tradeValue.Delta);
			UserStatsService.UpdateStats(stats);

			if (statEarned != null)
			{
				statEarned(this, new EarnStatEventArgs(tradeValue.Unit, tradeValue.Delta));
			}

			return new ITradeValue[] { tradeValue };
		}

		protected UserStatTradeValue NormalizeTradeValue(UserStatTradeValue tradeValue, IOperationContext context, int quantity = 1)
		{
			if (tradeValue.Function != null)
			{
				return new UserStatTradeValue(tradeValue.Unit, (int) FunctionEvaluator.Eval(tradeValue.Function, context) * quantity);
			}
			else
			{
				return new UserStatTradeValue(tradeValue.Unit, tradeValue.Delta * quantity);
			}
		}
	}
}
